package com.lin.filegraph.utils.parser.astvisitor;

import com.lin.filegraph.utils.parser.astvisitor.CommentVisitor;
import com.lin.filegraph.utils.parser.node.JMethodNode;
import com.lin.filegraph.utils.parser.node.JParameterNode;
import com.lin.filegraph.utils.parser.node.JTypeNode;
import org.eclipse.jdt.core.dom.*;

import java.lang.reflect.Modifier;
import java.util.List;

/**
 * @description:
 * @author: linhuaixu
 * @time: 2023/5/18 14:10
 */

public class MethodVisitor {

    private JTypeNode typeNode;

    public MethodVisitor(JTypeNode typeNode) {
        this.typeNode = typeNode;
    }

    public void visit(MethodDeclaration node) {
        if (node.resolveBinding() != null) {
            String filePath = typeNode.getFilePath();
            String methodName = node.getName().toString();
            String qualifiedName = typeNode.getTypeName() + "." +methodName;
            String methodSignature = node.resolveBinding().toString();
            String modifier = Modifier.toString(node.resolveBinding().getModifiers());
            String returnType = node.resolveBinding().getReturnType().getBinaryName();
            JMethodNode.MethodClassification methodClassification = null;

            if (node.isConstructor()) {
                methodClassification = JMethodNode.MethodClassification.isConstructor;
            } else {
                methodClassification = JMethodNode.MethodClassification.isCommon;
            }
            boolean isAPI = false;
            boolean hasComment = new CommentVisitor(node).isHasComment();
            if (modifier.contains("public") && typeNode.getModifier().contains("public")) {
                isAPI = true;
            }
            JMethodNode methodNode = new JMethodNode(filePath, node, methodName, qualifiedName, methodSignature, modifier,
                    returnType, methodClassification, isAPI, hasComment);
            typeNode.addChildNode(methodNode);

            if (!node.parameters().isEmpty()) {
                List<? extends ASTNode> parameters = node.parameters();
                for (ASTNode para : parameters) {
                    SingleVariableDeclaration singleVariable = (SingleVariableDeclaration) para;
                    if (singleVariable.resolveBinding() != null) {
                        String parameterName = singleVariable.resolveBinding().getName();
                        String parameterType = singleVariable.resolveBinding().getType().getQualifiedName();
                        JParameterNode parameterNode = new JParameterNode(filePath, singleVariable,
                                parameterName.toString(), parameterType);
                        methodNode.addChildNode(parameterNode);
                    }
                }
            }

        }
    }

    public void visit(Initializer node) {
        String filePath = typeNode.getFilePath();
        String methodName = "Initializer" + node.getStartPosition();
        String qualifiedName = typeNode.getTypeName() + "." + methodName;
        String methodSignature = methodName;
        String modifier = Modifier.toString(node.getModifiers());
        String returnType = "void";
        JMethodNode.MethodClassification methodClassification = JMethodNode.MethodClassification.isInitializer;
        boolean isAPI = false;
        boolean hasComment = new CommentVisitor(node).isHasComment();
        if (modifier.contains("public") && typeNode.getModifier().contains("public")) {
            isAPI = true;
        }
        JMethodNode methodNode = new JMethodNode(filePath, node, methodName, qualifiedName, methodSignature, modifier,
                returnType, methodClassification, isAPI, hasComment);
        typeNode.addChildNode(methodNode);

    }

    public void traverseMethods() {
        if (typeNode.getAstNode() instanceof TypeDeclaration) {
            TypeDeclaration typeDeclaration = (TypeDeclaration) typeNode.getAstNode();
            for (Object bodyDeclaration : typeDeclaration.bodyDeclarations()) {
                if (bodyDeclaration instanceof MethodDeclaration) {
                    visit((MethodDeclaration) bodyDeclaration);
                }
                if (bodyDeclaration instanceof Initializer) {
                    visit((Initializer) bodyDeclaration);
                }
            }
        }
        if (typeNode.getAstNode() instanceof AnonymousClassDeclaration) {
            AnonymousClassDeclaration anonymousClassDeclaration = (AnonymousClassDeclaration) typeNode.getAstNode();
            for (Object bodyDeclaration : anonymousClassDeclaration.bodyDeclarations()) {
                if (bodyDeclaration instanceof MethodDeclaration) {
                    visit((MethodDeclaration) bodyDeclaration);
                }
                if (bodyDeclaration instanceof Initializer) {
                    visit((Initializer) bodyDeclaration);
                }
            }
        }
        if (typeNode.getAstNode() instanceof EnumDeclaration) {
            EnumDeclaration enumDeclaration = (EnumDeclaration) typeNode.getAstNode();
            for (Object bodyDeclaration : enumDeclaration.bodyDeclarations()) {
                if (bodyDeclaration instanceof MethodDeclaration) {
                    visit((MethodDeclaration) bodyDeclaration);
                }
                if (bodyDeclaration instanceof Initializer) {
                    visit((Initializer) bodyDeclaration);
                }
            }
        }
    }
}

